#include "TetrisBoard.h"
#include "TetrisGame.h"
#include "TetrisBlock.h"

TetrisBoard::TetrisBoard(TetrisGame* game)
	: game_(game),
	pos_(4,0)
{
}


TetrisBoard::~TetrisBoard(void)
{
	Release();
}

/**
@brief 테트리스 Board와 Stage를 초기화 한다
@date 2013/01/24
@author 임진영(deviak@deviak.com)
@return void
*/
void TetrisBoard::Init()
{
	for( int i = 0; i < kTetrisBoardHeight; ++i )
	{
		for( int j = 0; j < kTetrisBoardWidth; ++j )
		{
			if( j == 0 || j == kTetrisBoardWidth - 1 )
			{
				board_[i][j] = 9;
				stage_[i][j] = 9;
			}
			else if( i == kTetrisBoardHeight-1 )
			{
				board_[i][j] = 9;
				stage_[i][j] = 9;
			}
			else
			{
				board_[i][j] = 0;
				stage_[i][j] = 0;
			}
		}
	}
}

/**
@brief board_를 stage_에 적용 시킨다
@remarks board_를 stage_에 적용 시킨 후 line을 검사한다
@date 2013/01/24
@author 임진영(deviak@deviak.com)
@return void
*/
void TetrisBoard::BlockOn()
{
	int i,j;
	for(i = 0; i<kTetrisBoardHeight; i++) {
		for(j = 0; j<kTetrisBoardWidth; j++) {
			stage_[i][j] = board_[i][j];
		}
	}

	CheckLine();				///< 줄이 채워졌는지 확인하며, 채워진 줄 수 만큼 score_를 증가 시키며 줄을 삭제한다

	for(i=0; i<kTetrisBoardHeight; i++){
		for(j=0; j<kTetrisBoardWidth; j++){
			board_[i][j]=stage_[i][j];
		}
	}
}

/**
@brief 줄이 채워졌는지 확인한다
@remarks 줄이 채워졌는지 확인하며, 채워진 줄 수 만큼 score_를 증가 시키며 줄을 삭제한다
@date 2013/01/24
@author 임진영(deviak@deviak.com)
@return void
*/
void TetrisBoard::CheckLine()
{
	int i,j,k;
	int comp;
	int lines=0;

	while(1){
		for(i=0; i<kTetrisBoardHeight-1; i++){
			comp=1;
			for(j=1;j<kTetrisBoardWidth-1;j++){
				if(stage_[i][j]==0){
					comp=0;
				}
			}
			if(comp==1)break;
		}
		if(comp==0)break;

		game_->IncreaseScore();

		for(j=1;j<kTetrisBoardWidth-1;j++){
			stage_[i][j]=0;
		}

		for(k=i;k>0;k--){
			for(j=1;j<kTetrisBoardWidth-1;j++){
				stage_[k][j]=stage_[k-1][j];
			}
		}
	}
}

/**
@brief Stage를 출력한다
@date 2013/01/24
@author 임진영(deviak@deviak.com)
@return void
*/
void TetrisBoard::Render()
{
	for( int i=0; i<kTetrisBoardHeight; ++i )
	{
		for( int j=0; j<kTetrisBoardWidth; ++j)
		{
			MoveCursor(POSITION(j,i));
			switch(board_[i][j]) {
			case 0:
				DrawObject(POSITION(j,i), ' ' );
				break;
			case 9:
				DrawObject(POSITION(j,i), 'M' );
				break;
			default:
				DrawObject(POSITION(j,i), 'O' );
				break;
			}
		}
	}
}


/**
@brief 메모리 해제
@date 2013/01/24
@author 임진영(deviak@deviak.com)
@return void
*/
void TetrisBoard::Release()
{
	game_ = NULL;
}

/**
@brief 메모리 해제
@date 2013/01/24
@author 임진영(deviak@deviak.com)
@return void
*/
bool TetrisBoard::CheckCreateBlock( const int* block ) 
{
	pos_ = POSITION(4,0);

	for(int i=0; i<4; i++) {
		for(int j=0; j<4; j++) {
			board_[i][j+4] = stage_[i][j+4] + block[(i*TetrisBlock::kBlockWidth)+j];
			if(board_[i][j+4] > 1) {
				game_->SetGameover(true);
				return true;
			}
		}
	}

	return false;
}

/**
@brief Block이 충돌이 났는지 검사한다
@date 2013/01/24
@author 임진영(deviak@deviak.com)
@param const POSITION & p, const int* block
@return bool
*/
bool TetrisBoard::CheckOver(const POSITION &p, const int* block)
{
	for(int i = 0; i<4; i++) {
		for(int j = 0; j<4; j++) {
			if(block[(i*TetrisBlock::kBlockWidth)+j]) {
				if(stage_[p.y_ + i][p.x_ + j] != 0) {
					return true;
				}
			}
		}
	}
	return false;
}

/**
@brief 테트리스 Block을 움직인다
@date 2013/01/24
@author 임진영(deviak@deviak.com)
@param const POSITION & p, const int* block
@return void
*/
void TetrisBoard::MoveBlock(const POSITION &p, const int* block)
{
	int i, j; 
	for(i = 0; i<4; i++) {
		for(j = 0; j<4; j++) {
			board_[pos_.y_+i][pos_.x_+j] -= block[(i*TetrisBlock::kBlockWidth)+j];
		}
	}

	pos_ = p;

	for(i = 0; i<4; i++) {
		for(j = 0; j<4; j++) {
			board_[pos_.y_+i][pos_.x_+j] += block[(i*TetrisBlock::kBlockWidth)+j];
		}
	}
}

/**
@brief 테트리스 Block을 회전시킨다
@date 2013/01/24
@author 임진영(deviak@deviak.com)
@return void
*/
void TetrisBoard::TurnBlock(int* tmp)
{
	int i,j;

	if(game_)
	{
		TetrisBlock* pBlock = game_->Block();
		if(pBlock)
		{
			const int* block = pBlock->Block();

			for(i=0; i<4; i++){
				for(j=0; j<4; j++){
					board_[pos_.y_+i][pos_.x_+j]-=tmp[(i*TetrisBlock::kBlockWidth)+j];
					board_[pos_.y_+i][pos_.x_+j]+=block[(i*TetrisBlock::kBlockWidth)+j];
				}
			}

		}
	}
}